 /*
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License");  you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  * http//www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  * the specific language governing rights and limitations under the License.
  *
  * The Original Code is ART Ontology API.
  *
  * The Initial Developer of the Original Code is University of Roma Tor Vergata.
  * Portions created by University of Roma Tor Vergata are Copyright (C) 2009.
  * All Rights Reserved.
  *
  * The ART Ontology API were developed by the Artificial Intelligence Research Group
  * (ai-nlp.info.uniroma2.it) at the University of Roma Tor Vergata
  * Current information about the ART Ontology API can be obtained at 
  * http//ai-nlp.info.uniroma2.it/software/...
  *
  */

  /*
   * Contributor(s): Armando Stellato stellato@info.uniroma2.it
  */
package it.uniroma2.art.owlart.models.impl;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.BaseRDFTripleModel;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.navigation.ARTLiteralIterator;
import it.uniroma2.art.owlart.navigation.ARTResourceIterator;
import it.uniroma2.art.owlart.navigation.ARTStatementIterator;
import it.uniroma2.art.owlart.navigation.ARTURIResourceIterator;
import it.uniroma2.art.owlart.vocabulary.OWL;
import it.uniroma2.art.owlart.vocabulary.RDF;
import it.uniroma2.art.owlart.vocabulary.RDFS;

public class OWLModelImpl extends RDFSModelImpl implements OWLModel {

    public OWLModelImpl(BaseRDFTripleModel baseRep) {
        super(baseRep);
    }

	/****************************
	/* ADD/REMOVE METHODS ***
	 ****************************/    
    
    public void addAnnotationProperty(String propertyURI, ARTURIResource superProperty, ARTResource... contexts) throws ModelUpdateException {
    	ARTURIResource newProp = baseRep.createURIResource(propertyURI);
    	baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.ANNOTATIONPROPERTY, contexts);
    	if (superProperty!=null)
    		baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, contexts);    	
    }
    
    public void addDatatypeProperty(String propertyURI, ARTURIResource superProperty, ARTResource... contexts) throws ModelUpdateException {
    	ARTURIResource newProp = baseRep.createURIResource(propertyURI);
    	baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.DATATYPEPROPERTY, contexts);
    	if (superProperty!=null)
    		baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, contexts);    	
    }
    
    public void addObjectProperty(String propertyURI, ARTURIResource superProperty, ARTResource... contexts) throws ModelUpdateException {
    	ARTURIResource newProp = baseRep.createURIResource(propertyURI);
    	baseRep.addTriple(newProp, RDF.Res.TYPE, OWL.Res.OBJECTPROPERTY, contexts);    
    	if (superProperty!=null)
    		baseRep.addTriple(newProp, RDFS.Res.SUBPROPERTYOF, superProperty, contexts);    	    		
    }

    public void addImportStatement(String baseURI, ARTResource... contexts) throws ModelUpdateException {
    	ARTURIResource importedRes = baseRep.createURIResource(baseURI);
    	baseRep.addTriple(baseRep.createURIResource(getBaseURI()), OWL.Res.IMPORTS, importedRes, contexts);
    }


    /* (non-Javadoc)
     * @see it.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#addNewClass(java.lang.String)
     * 
     * while the RDFS adds a rdfs:Class, this one adds an owl:Class
     */
    @Override
    public void addClass(String uri, ARTResource... contexts) throws ModelUpdateException {
        ARTURIResource newClass = baseRep.createURIResource(uri);
        baseRep.addTriple(newClass, RDF.Res.TYPE, OWL.Res.CLASS, contexts);
    }
    

    public void removeImportStatement(ARTURIResource URI, ARTResource... contexts) throws ModelUpdateException {
        baseRep.deleteTriple(baseRep.createURIResource(getBaseURI()) , OWL.Res.IMPORTS, URI, contexts);
    }
    
    
    /**************************************
    /*   TRIPLE INSTANTIATION METHODS   ***
     **************************************/
    
    
    public void instantiateDatatypeProperty(ARTResource subject, ARTURIResource predicate, String literalString, ARTResource... contexts) throws ModelUpdateException {
        ARTLiteral lit = baseRep.createLiteral(literalString);
        baseRep.addTriple(subject, predicate, lit, contexts);
    }

    public void instantiateObjectProperty(ARTResource subject, ARTURIResource predicate, ARTResource object, ARTResource... contexts) throws ModelUpdateException {
        baseRep.addTriple(subject, predicate, object, contexts);
    }
    
    public void instantiateAnnotationProperty(ARTResource subject, ARTURIResource property, String value, String lang, ARTResource... contexts) throws ModelUpdateException {
        ARTLiteral lit = baseRep.createLiteral(value, lang);
        baseRep.addTriple(subject, property, lit, contexts);        
    }
    
	/*************************
	/*   BOOLEAN METHODS   ***
	 *************************/
    
    public boolean isAnnotationProperty(ARTURIResource prop, ARTResource... contexts) throws ModelAccessException {
        return baseRep.hasTriple(prop, RDF.Res.TYPE, OWL.Res.ANNOTATIONPROPERTY, true, contexts);
    }

    public boolean isDatatypeProperty(ARTURIResource prop, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(prop, RDF.Res.TYPE, OWL.Res.DATATYPEPROPERTY, true, contexts);
    }

    public boolean isFunctionalProperty(ARTURIResource property, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.FUNCTIONALPROPERTY, true, contexts);
    }

    public boolean isInverseFunctionalProperty(ARTURIResource property, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.INVERSEFUNCTIONALPROPERTY, true, contexts);
    }

    public boolean isObjectProperty(ARTURIResource property, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.OBJECTPROPERTY, true, contexts);
    }

    public boolean isSymmetricProperty(ARTURIResource property, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.SYMMETRICPROPERTY, true, contexts);
    }

    public boolean isTransitiveProperty(ARTURIResource property, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(property, RDF.Res.TYPE, OWL.Res.TRANSITIVEPROPERTY, true, contexts);
    }
    
    public boolean isOntology(ARTURIResource uri, ARTResource... contexts) throws ModelAccessException {
    	return baseRep.hasTriple(uri, RDF.Res.TYPE, OWL.Res.ONTOLOGY, true, contexts);
    }

    
    /*************************
    /*   LIST/GET METHODS  ***
     *************************/
    
    
    /* (non-Javadoc)
     * @see it.uniroma2.art.owlart.models.OWLModel#listAnnotationProperties(boolean, it.uniroma2.art.owlart.model.ARTResource[])
     */
    public ARTURIResourceIterator listAnnotationProperties(boolean inferred, ARTResource... contexts) throws ModelAccessException {
        return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator( baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, OWL.Res.ANNOTATIONPROPERTY, inferred, contexts) ) );
    }
    
    public ARTURIResourceIterator listDatatypeProperties(boolean inferred, ARTResource... contexts) throws ModelAccessException {
        return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator( baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, OWL.Res.DATATYPEPROPERTY, inferred, contexts) ) );
    }

    public ARTURIResourceIterator listObjectProperties(boolean inferred, ARTResource... contexts) throws ModelAccessException {
        return new URIResourceIteratorWrappingResourceIterator(new SubjectsOfStatementsIterator( baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, OWL.Res.OBJECTPROPERTY, inferred, contexts) ) );
    }

    public ARTURIResourceIterator listOntologyImports(ARTURIResource ontology, ARTResource... contexts) throws ModelAccessException {
        return new URIResourceIteratorWrappingNodeIterator ( new ObjectsOfStatementsIterator( baseRep.listStatements(ontology, OWL.Res.IMPORTS, NodeFilters.ANY, false, contexts) ) );
    }

    public ARTLiteralIterator listValuesOfSubjDTypePropertyPair(ARTResource instance, ARTURIResource property, boolean inferred, ARTResource... contexts) throws ModelAccessException {
        return new LiteralIteratorWrappingNodeIterator( new ObjectsOfStatementsIterator( baseRep.listStatements(instance, property, NodeFilters.ANY, inferred, contexts) ) );
    }

    public ARTResourceIterator listValuesOfSubjObjPropertyPair(ARTResource individual, ARTURIResource property, boolean inferred, ARTResource... contexts) throws ModelAccessException {
        return new ResourceIteratorWrappingNodeIterator ( new ObjectsOfStatementsIterator( baseRep.listStatements(individual, property, NodeFilters.ANY, inferred, contexts) ) );
    }

    //if infer==true then retrieves all rdfs classes, otherwise retrieves all owl:class TODO in non-infer mode, should do some trivial owl+rdfs classes
    public ARTURIResourceIterator listNamedClasses(boolean inferred, ARTResource... graphs) throws ModelAccessException {
        if (inferred == true)
        	return new URIResourceIteratorFilteringResourceIterator( new SubjectsOfStatementsIterator( baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, RDFS.Res.CLASS, inferred, graphs ) ) );
        else            
            return new URIResourceIteratorFilteringResourceIterator( new SubjectsOfStatementsIterator( baseRep.listStatements(NodeFilters.ANY, RDF.Res.TYPE, OWL.Res.CLASS, inferred, graphs ) ) );
    }
    
    
    /* (non-Javadoc)
     * @see it.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#retrieveClass(java.lang.String)
     * 
     * this implementation tries to makedo with the possibile lackness of a reasoner, so that owl classes would not be recognized as rdfs classes
     */
    @Override
    public ARTURIResource retrieveClass(String uri, ARTResource... contexts) throws ModelAccessException {
        ARTStatementIterator statIt = baseRep.listStatements(baseRep.createURIResource(uri), RDF.Res.TYPE, RDFS.Res.CLASS, false, contexts);
        if (statIt.streamOpen()) {        	
            ARTURIResource cls = statIt.next().getSubject().asURIResource();
            statIt.close();
            return cls;
        }

        statIt = baseRep.listStatements(baseRep.createURIResource(uri), RDF.Res.TYPE, OWL.Res.CLASS, false, contexts);
        if (statIt.streamOpen()) {        	
            ARTURIResource cls = statIt.next().getSubject().asURIResource();
            statIt.close();
            return cls;
        }
        
        return null;
    }
    
    /* (non-Javadoc)
     * @see it.uniroma2.art.ontapi.repository.impl.ARTRDFSRepositoryImpl#isClass(it.uniroma2.art.ontapi.model.ARTResource)
     * 
     * this implementation tries to makedo with the possibile lackness of a reasoner, so that owl classes would not be recognized as rdfs classes
     */
    @Override
    public boolean isClass(ARTResource cls, ARTResource... contexts) throws ModelAccessException {
        if (baseRep.hasTriple(cls, RDF.Res.TYPE, RDFS.Res.CLASS, true, contexts) )
            return true;
        else
            return baseRep.hasTriple(cls, RDF.Res.TYPE, OWL.Res.CLASS, true, contexts);
    }


}
